#include "decode.h"

Decoder::Decoder()
{
    AVCodec *pCodec;
    AVCodecID codec_id = AV_CODEC_ID_H264;
    avcodec_register_all();
    pCodec = avcodec_find_decoder(codec_id);
    if (!pCodec)
    {
        fprintf(stderr, "Codec not found\n");
        return;
    }
    pCodecCtx = avcodec_alloc_context3(pCodec);
    if (!pCodecCtx)
    {
        fprintf(stderr, "Could not allocate video codec context\n");
        return;
    }

    pCodecParserCtx = av_parser_init(codec_id);
    if (!pCodecParserCtx)
    {
        fprintf(stderr, "Could not allocate video parser context\n");
        return;
    }

    if (pCodec->capabilities & AV_CODEC_FLAG_TRUNCATED)
        pCodecCtx->flags |= AV_CODEC_FLAG_TRUNCATED; /* we do not send complete frames */

    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        fprintf(stderr, "Could not open codec\n");
        return;
    }

    pFrame = av_frame_alloc();
    av_init_packet(&packet);
    pFrameBGR = av_frame_alloc(); //存储解码后转换的RGB数据
}

int Decoder::loop(uint8_t *cur_ptr, int cur_size, uint8_t *out_ptr, int *out_size, int *width, int *height)
{
    int len = av_parser_parse2(
        pCodecParserCtx, pCodecCtx,
        &packet.data, &packet.size,
        cur_ptr, cur_size,
        AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);

    fprintf(stderr, "len = %d\n", len);
    cur_ptr += len;
    cur_size -= len;

    fprintf(stderr, "packet.size = %d\n", packet.size);
    if (packet.size == 0)
        return -1;

    //Some Info from AVCodecParserContext
    switch (pCodecParserCtx->pict_type)
    {
    case AV_PICTURE_TYPE_I:
        fprintf(stderr, "Type: I\t");
        break;
    case AV_PICTURE_TYPE_P:
        fprintf(stderr, "Type: P\t");
        break;
    case AV_PICTURE_TYPE_B:
        fprintf(stderr, "Type: B\t");
        break;
    default:
        fprintf(stderr, "Type: Other\t");
        break;
    }
    fprintf(stderr, "Output Number:%4d\t", pCodecParserCtx->output_picture_number);
    fprintf(stderr, "Offset:%8ld\n", pCodecParserCtx->cur_offset);

    int ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);
    if (ret < 0)
    {
        fprintf(stderr, "Decode Error.(解码错误)\n");
        return ret;
    }
    if (got_picture)
    {
        if (first_time)
        {
            fprintf(stderr, "\nCodec Full Name:%s\n", pCodecCtx->codec->long_name);
            fprintf(stderr, "width:%d\nheight:%d\n\n", pCodecCtx->width, pCodecCtx->height);
            img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);

            size = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
            out_buffer = (uint8_t *)av_malloc(size);
            avpicture_fill((AVPicture *)pFrameBGR, out_buffer, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); // allocator memory for BGR buffer
            first_time = 0;
        }

        fprintf(stderr, "Succeed to decode 1 frame!\n");
        sws_scale(img_convert_ctx, (const uint8_t *const *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameBGR->data, pFrameBGR->linesize);
        memcpy(out_ptr, out_buffer, size);
        *out_size = size;
        *width = pCodecCtx->width;
        *height = pCodecCtx->height;
    }
    return 0;
}

Decoder::~Decoder()
{
    packet.data = NULL;
    packet.size = 0;

    sws_freeContext(img_convert_ctx);
    av_parser_close(pCodecParserCtx);

    //av_frame_free(&pFrameYUV);
    av_frame_free(&pFrameBGR);
    av_frame_free(&pFrame);
    avcodec_close(pCodecCtx);
    av_free(pCodecCtx);
    av_free(out_buffer);
}
